﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace PLBrowse
{
    /// <summary>
    /// 计算模型AA BB包围盒
    /// </summary>
    public class MeshAABBTool
    {
        public static MeshAABB CalAABBAry(MeshFilter[] meshAry, Vector3 origin)
        {
            List<MeshAABB> aabb = new List<MeshAABB>();
            foreach (var item in meshAry)
            {
                List<Vector3> vectorList = new List<Vector3>();
                try
                {
                    item.sharedMesh.GetVertices(vectorList);
                }
                catch (Exception ex)
                {
                    Debug.LogError(ex.Message);
                }

                aabb.Add(CalAABB(vectorList, item.transform.position));
            }

            MeshAABB newAABB = new MeshAABB();
            float maxX = 0;
            float maxY = 0;
            float maxZ = 0;
            float minX = 0;
            float minY = 0;
            float minZ = 0;
            for (int i = 0; i < aabb.Count; i++)
            {
                var mesh = aabb[i];
                if (i == 0)
                {
                    minX = mesh.WorldMinX;
                    minY = mesh.WorldMinY;
                    minZ = mesh.WorldMinZ;
                    maxX = mesh.WorldMaxX;
                    maxY = mesh.WorldMaxY;
                    maxZ = mesh.WorldMaxZ;
                    continue;
                }

                if (mesh.WorldMinX < minX)
                    minX = mesh.WorldMinX;
                if (mesh.WorldMinY < minY)
                    minY = mesh.WorldMinY;
                if (mesh.WorldMinZ < minZ)
                    minZ = mesh.WorldMinZ;
                if (mesh.WorldMaxX > maxX)
                    maxX = mesh.WorldMaxX;
                if (mesh.WorldMaxY > maxY)
                    maxY = mesh.WorldMaxY;
                if (mesh.WorldMaxZ > maxZ)
                    maxZ = mesh.WorldMaxZ;
            }

            var dir = origin - Vector3.zero;

            minX = minX - dir.x;
            minY = minY - dir.y;
            minZ = minZ - dir.z;
            maxX = maxX - dir.x;
            maxY = maxY - dir.y;
            maxZ = maxZ - dir.z;

            newAABB.SetEightPoint(minX, minY, minZ, maxX, maxY, maxZ, origin);
            //重新计算

            return newAABB;
        }

        public static MeshAABB CalAABB(List<Vector3> vList)
        {
            return CalAABB(vList, Vector3.zero);
        }

        public static MeshAABB CalAABB(List<Vector3> vList, Vector3 origin)
        {
            MeshAABB mesh = new MeshAABB();

            float maxX = 0;
            float minX = 0;
            float maxY = 0;
            float minY = 0;
            float maxZ = 0;
            float minZ = 0;

            for (int i = 0; i < vList.Count; i++)
            {
                Vector3 v = vList[i];
                if (i == 0)
                {
                    minX = v.x;
                    minY = v.y;
                    minZ = v.z;
                    maxX = v.x;
                    maxY = v.y;
                    maxZ = v.z;
                    continue;
                }

                if (v.x < minX)
                    minX = v.x;
                if (v.y < minY)
                    minY = v.y;
                if (v.z < minZ)
                    minZ = v.z;
                if (v.x > maxX)
                    maxX = v.x;
                if (v.y > maxY)
                    maxY = v.y;
                if (v.z > maxZ)
                    maxZ = v.z;
            }


            mesh.SetEightPoint(minX, minY, minZ, maxX, maxY, maxZ, origin);

            return mesh;
        }
    }

    public class MeshAABB
    {
        public float maxX = 0;
        public float minX = 0;
        public float maxY = 0;
        public float minY = 0;
        public float maxZ = 0;
        public float minZ = 0;

        public float WorldMaxX
        {
            get { return maxX + center.x; }
        }

        public float WorldMinX
        {
            get { return minX + center.x; }
        }

        public float WorldMaxY
        {
            get { return maxY + center.y; }
        }

        public float WorldMinY
        {
            get { return minY + center.y; }
        }

        public float WorldMaxZ
        {
            get { return maxZ + center.z; }
        }

        public float WorldMinZ
        {
            get { return minZ + center.z; }
        }

        public Vector3 bottomLeft;
        public Vector3 bottomRight;
        public Vector3 bottomFrontLeft;
        public Vector3 bottomFrontRight;

        public Vector3 upLeft;
        public Vector3 upRight;
        public Vector3 upFrontLeft;
        public Vector3 upFrontRight;

        /// <summary>
        /// Collider 的size
        /// </summary>
        public Vector3 size;

        /// <summary>
        /// 模型的世界坐标
        /// </summary>
        public Vector3 center;

        public Vector3 meshCenter;

        public void SetEightPoint(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
        {
            SetEightPoint(minX, minY, minZ, maxX, maxY, maxZ, center);
        }

        public void SetEightPoint(float minX, float minY, float minZ, float maxX, float maxY, float maxZ,
            Vector3 origin)
        {
            this.minX = minX;
            this.minY = minY;
            this.minZ = minZ;

            this.maxX = maxX;
            this.maxY = maxY;
            this.maxZ = maxZ;

            float disX = (maxX + Math.Abs(minX));
            float disY = (maxY + Math.Abs(minY));
            float disZ = (maxZ + Math.Abs(minZ));
            size = new Vector3(disX, disY, disZ);
            center = origin;

            meshCenter.x = (maxX + minX) / 2;
            meshCenter.y = (maxY + minY) / 2;
            meshCenter.z = (maxZ + minZ) / 2;

            bottomLeft = new Vector3(minX, minY, minZ) + origin;
            bottomRight = new Vector3(maxX, minY, minZ) + origin;
            bottomFrontLeft = new Vector3(minX, minY, maxZ) + origin;
            bottomFrontRight = new Vector3(maxX, minY, maxZ) + origin;

            upLeft = new Vector3(minX, maxY, minZ) + origin;
            upRight = new Vector3(maxX, maxY, minZ) + origin;
            upFrontLeft = new Vector3(minX, maxY, maxZ) + origin;
            upFrontRight = new Vector3(maxX, maxY, maxZ) + origin;
        }
    }
}